﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace SharpSoft.WPF.Controls
{
    /// <summary>
    /// 能产生随机曲线的图像
    /// </summary>
    public class RandomCurveImage : Image
    {
        public RandomCurveImage()
        {

            this.random = new Random();
            this.timeTracker = new TimeTracker();
            this.timeTracker.TimerFired += TimeTracker_TimerFired;
            CompositionTarget.Rendering += CompositionTarget_Rendering;

            ///将Bitmap绑定到当前图像控件的Source
            Binding bmpBinding = new Binding("Bitmap") { Source = this };
            this.SetBinding(SourceProperty, bmpBinding);


            originPoints = this.OnInterpolate();
        }
        private readonly TimeTracker timeTracker;//更新时间控制
        private readonly Random random;
        private Point[] originPoints;//原始点（插值后）
        private Point[] lastFrame;//上一帧的点

        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);
            if (e.Property == PointsProperty || e.Property == InterpolationCountProperty || e.Property == InterpolationRandomOffsetProperty)
            {
                originPoints = this.OnInterpolate();
            }
        }

        private void TimeTracker_TimerFired(object sender, EventArgs e)
        {
            this.OnUpdate(this.timeTracker.DeltaSeconds);
        }

        private void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            this.timeTracker.Update();
        }

        protected virtual void OnUpdate(double seconds)
        {
            if (this.Bitmap == null)
            {
                return;
            }

            using (this.Bitmap.GetBitmapContext())
            {
                this.Bitmap.Clear(Colors.Transparent);

                if (lastFrame == null)
                {
                    lastFrame = new Point[originPoints.Length];
                    for (int i = 0; i < originPoints.Length; i++)
                    {
                        lastFrame[i] = originPoints[i];
                    }
                }
                var curFrame = new Point[lastFrame.Length];
                var maxOffset = this.MaxOffset;
                var maxVelocity = this.MaxVelocity;
                var t = seconds * 10d;//以100ms计
                for (int i = 0; i < lastFrame.Length; i++)
                {
                    var p = lastFrame[i];
                    if ((p - originPoints[i]).Length >= maxOffset)
                    {//点移动已经超过了最大偏移，开始向原点靠拢，避免超出范围。
                        var vo = originPoints[i] - p;
                        var o = vo * (maxOffset / vo.Length);
                        curFrame[i] = p + o;
                    }
                    else
                    {
                        var ox = random.NextDouble() * maxVelocity * t;
                        var oy = random.NextDouble() * maxVelocity * t;
                        var o = new Vector(ox, oy);//当前帧此点的偏移
                        curFrame[i] = p + o;
                    }
                }
                lastFrame = curFrame;
                var data = this.GetPointsData(curFrame);
                this.Bitmap.DrawCurveClosed(data, (float)this.Tension, this.Color);
            }

        }

        /// <summary>
        /// 对指定的点和参数进行插值
        /// </summary>
        /// <returns></returns>
        private Point[] OnInterpolate()
        {
            var count = this.InterpolationCount + this.random.Next(0, this.InterpolationRandomOffset + 1);
            List<Point> ps = new List<Point>();
            if (this.Points == null)
            {
                return ps.ToArray();
            }
            for (int i = 0; i < this.Points.Length; i++)
            {
                var ni = i + 1;
                if (ni >= this.Points.Length)
                {
                    ni = 0;
                }
                var p = this.Points[i];
                var np = this.Points[ni];
                var vo = (np - p) / count;
                for (int j = 0; j < count; j++)
                {
                    ps.Add(p + (vo * j));
                }
            }
            return ps.ToArray();
        }


        /// <summary>
        /// 获取当前位图
        /// </summary>
        public WriteableBitmap Bitmap
        {
            get { return (WriteableBitmap)GetValue(BitmapProperty); }
            private set { SetValue(BitmapProperty, value); }
        }

        public static readonly DependencyProperty BitmapProperty =
            DependencyProperty.Register("Bitmap", typeof(WriteableBitmap), typeof(RandomCurveImage), new PropertyMetadata(null));


        /// <summary>
        /// 曲线颜色
        /// </summary>
        public Color Color
        {
            get { return (Color)GetValue(ColorProperty); }
            set { SetValue(ColorProperty, value); }
        }

        public static readonly DependencyProperty ColorProperty =
            DependencyProperty.Register("Color", typeof(Color), typeof(RandomCurveImage), new PropertyMetadata(Colors.Red));


        /// <summary>
        /// 曲线拉力
        /// </summary> 
        public double Tension
        {
            get { return (double)GetValue(TensionProperty); }
            set { SetValue(TensionProperty, value); }
        }

        public static readonly DependencyProperty TensionProperty =
            DependencyProperty.Register("Tension", typeof(double), typeof(RandomCurveImage), new PropertyMetadata(0.3d));



        /// <summary>
        /// 获取或设置当前曲线需要经过的点（点坐标使用浮点相对坐标，1表示当前图像的宽度或高度）
        /// </summary>
        public Point[] Points
        {
            get { return (Point[])GetValue(PointsProperty); }
            set { SetValue(PointsProperty, value); }
        }

        public static readonly DependencyProperty PointsProperty =
            DependencyProperty.Register("Points", typeof(Point[]), typeof(RandomCurveImage), new PropertyMetadata(new Point[] { new Point(0.1, 0.1), new Point(0.9, 0.1), new Point(0.9, 0.9), new Point(0.1, 0.9) }));


        /// <summary>
        /// 插值数量（在每两个指定的点之间插入随机点的数量）
        /// </summary>
        public int InterpolationCount
        {
            get { return (int)GetValue(InterpolationCountProperty); }
            set { SetValue(InterpolationCountProperty, value); }
        }

        public static readonly DependencyProperty InterpolationCountProperty =
            DependencyProperty.Register("InterpolationCount", typeof(int), typeof(RandomCurveImage), new PropertyMetadata(5));


        /// <summary>
        /// 插值随机偏移量（在指定的插值数量基础上，加上一个随机的偏移量，这个属性是这个随机偏移量的最大可能值）
        /// </summary>
        public int InterpolationRandomOffset
        {
            get { return (int)GetValue(InterpolationRandomOffsetProperty); }
            set { SetValue(InterpolationRandomOffsetProperty, value); }
        }

        public static readonly DependencyProperty InterpolationRandomOffsetProperty =
            DependencyProperty.Register("InterpolationRandomOffset", typeof(int), typeof(RandomCurveImage), new PropertyMetadata(0));


        /// <summary>
        /// 坐标点最大的偏移距离
        /// </summary>
        public double MaxOffset
        {
            get { return (double)GetValue(MaxOffsetProperty); }
            set { SetValue(MaxOffsetProperty, value); }
        }

        public static readonly DependencyProperty MaxOffsetProperty =
            DependencyProperty.Register("MaxOffset", typeof(double), typeof(RandomCurveImage), new PropertyMetadata(0.06d));


        /// <summary>
        /// 坐标点移动的最大速度（百分比单位/100ms）
        /// </summary>
        public double MaxVelocity
        {
            get { return (double)GetValue(MaxVelocityProperty); }
            set { SetValue(MaxVelocityProperty, value); }
        }

        public static readonly DependencyProperty MaxVelocityProperty =
            DependencyProperty.Register("MaxVelocity", typeof(double), typeof(RandomCurveImage), new PropertyMetadata(0.05d));



        /// <summary>
        /// 获取或设置位图最短更新间隔
        /// </summary>
        public TimeSpan UpdateInterval { get => this.timeTracker.Interval; set => this.timeTracker.Interval = value; }


        /// <summary>
        /// 获取用于渲染曲线的点数据
        /// </summary>
        /// <param name="points"></param>
        /// <returns></returns>
        int[] GetPointsData(Point[] points)
        {
            int[] ps = new int[points.Length * 2];
            for (int i = 0; i < points.Length; i++)
            {
                ps[i * 2] = (int)(points[i].X * this.ActualWidth);
                ps[i * 2 + 1] = (int)(points[i].Y * this.ActualHeight);
            }
            return ps;
        }

        protected override Size MeasureOverride(Size constraint)
        {
            return constraint;
            // return base.MeasureOverride(constraint);
        }

        protected override Size ArrangeOverride(Size arrangeSize)
        {
            return arrangeSize;
        }

        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
        {
            base.OnRenderSizeChanged(sizeInfo);
            var w = (int)this.ActualWidth;
            var h = (int)this.ActualHeight;
            //尺寸改变后重置图像大小
            this.Bitmap = BitmapFactory.New(w, h);
            //using (this.Bitmap.GetBitmapContext())
            //{
            //    this.Bitmap.Clear(Colors.Transparent);
            //}
        }
    }
}
